package com.mxx.common.websecurity;

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @Auther: Mr. Zeng
 * @Date: 2020/5/19 10:19
 * @Description: 暂无描述
 */

@Slf4j
public class AuthenticationValidateCodeProvider extends AbstractUserDetailsAuthenticationProvider {

    private UserDetailsService userDetailsService;
    private AuthenticationParameter parameter;
    private final String failureOfEmpty = "verifyCode is null or empty";
    private final String failureOfTimeout = "verifyCode time out";
    private final String failureOfValidate = "verifyCode validate fail";

    public AuthenticationValidateCodeProvider(UserDetailsService userDetailsService, AuthenticationParameter parameter) {
        this.userDetailsService = userDetailsService;
        this.parameter = parameter;
    }

    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {

    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        AuthenticationValidateCodeDetails authenticationValidateCodeDetails = (AuthenticationValidateCodeDetails) authentication.getDetails();
        String verifyCode = authenticationValidateCodeDetails.getValidateValue();
        if (verifyCode == null || verifyCode.isEmpty()) {
            log.error(failureOfEmpty);
            throw new DisabledException(failureOfEmpty);
        }

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String inputVerifyCode = (String) request.getSession().getAttribute(parameter.getStorageName());
        if (inputVerifyCode == null || inputVerifyCode.isEmpty()) {
            log.warn(failureOfTimeout);
            throw new DisabledException(failureOfTimeout);
        }

        if (!inputVerifyCode.toLowerCase().equals(verifyCode.toLowerCase())) {
            log.warn(failureOfValidate);
            throw new DisabledException(failureOfValidate);
        }
        return super.authenticate(authentication);
    }

    @Override
    protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        try {
            UserDetails loadedUser = userDetailsService.loadUserByUsername(username);
            if (loadedUser == null) {
                throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation");
            } else {
                return loadedUser;
            }
        } catch (UsernameNotFoundException var4) {
            throw var4;
        } catch (InternalAuthenticationServiceException var5) {
            throw var5;
        } catch (Exception var6) {
            throw new InternalAuthenticationServiceException(var6.getMessage(), var6);
        }
    }
}
